package com.aldobucchi.utils.priority
{
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import com.aldobucchi.core.markers.ISingleton;
	import com.aldobucchi.core.os.thread.Thread;
	
	/**
	 * 
	 * TODO: react to display list rearrangements ( reparenting )
	 * TODO: react to visible/invisible and add/remove
	 * 			for now we are only detecting the first added to stage
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class DisplayListPriorityManager implements ISingleton
	{




		private var dobj2priority	:Dictionary = new Dictionary( true );

		private var query2dobj		:Dictionary = new Dictionary( true );



		public function setDisplayObjectPriority( dobj:DisplayObject, priority:uint ):void
		{
			dobj2priority[ dobj ] = priority;
			refreshDown( dobj );		
		}


		
		public function bindQueryToDisplayObject( query:IPrioritizable, dobj:DisplayObject ):void
		{
			query2dobj[ query ] = dobj;
			query.priority = getDisplayObjectPriority( dobj );
		
			dobj.addEventListener( Event.ADDED_TO_STAGE, dobj_addedToStage, false, 0, true );
			dobj.addEventListener( Event.REMOVED_FROM_STAGE, dobj_removedFromStage, false, 0, true );
		
		}
		
		
		


		private function refreshDown( dobj:DisplayObject ):void
		{

			var p:uint = getDisplayObjectPriority( dobj );

			for ( var k:* in query2dobj )
			{
				var query:IPrioritizable = k as IPrioritizable;
				if ( query2dobj[ query ] == dobj )
				{
					query.priority = p;
				}
			}
			
			
			if ( dobj is DisplayObjectContainer )
			{
				var c:DisplayObjectContainer = dobj as DisplayObjectContainer;
				for ( var i:int=0; i<c.numChildren; i++ )
					refreshDown( c.getChildAt( i ) );
			}
		
		}




		private function getDisplayObjectPriority( dobj:DisplayObject ):uint
		{

			if ( dobj.stage == null )
			{
				return 0;		
			}
	

			if ( ! isNaN( dobj2priority[ dobj ] ) )
				return dobj2priority[ dobj ];
				
			if ( dobj.parent )
				return getDisplayObjectPriority( dobj.parent );
				
			return Thread.NORM_PRIORITY;
		
		}




		private function dobj_addedToStage( event:Event ):void
		{
			refreshDown( event.target as DisplayObject );
		}

		private function dobj_removedFromStage( event:Event ):void
		{
			refreshDown( event.target as DisplayObject );
		}		






		private static var _i:DisplayListPriorityManager;
		
		public static function get i( ):DisplayListPriorityManager
		{
			if ( _i == null )
				_i = new DisplayListPriorityManager( );
			return _i;
		}





	}


}

